package org.syncsoft.overalt.communication.api;

import java.util.ArrayList;
import java.util.Collection;

import org.syncsoft.overalt.common.api.Configuration;

/**
 * build new connections
 * 
 * @pattern factory
 * @author tptfc
 *
 */
public class ConnectionPool {
	private static ThreadLocal<Connection> connections;
	private static Collection<Connection> poolConnections;
	
	static {
		setConnections(new ThreadLocal<Connection>());
		
		Collection<Connection> connections = new ArrayList<Connection>();
		for (int i = 0; i < Configuration.getMaxPoolConnections(); i++) {
			connections.add(new Connection(Configuration.getUrlConnection()));
		}
		
		setPoolConnections(connections);
	}
	
	/**
	 * @postcondition add a connection in ThreadLocal
	 * @return new connection
	 */
	public static synchronized Connection getConnection() {
		
		Connection connection = getConnections().get();
		
		while (connection == null) {
			for (Connection poolConnection : getPoolConnections()) {
				if (!poolConnection.isInUse()) {
					connection = poolConnection;
				}
			}
			
			waitTime(200);
		}
		
		connection.setInUse(true);
		openConnection(connection);
		getConnections().set(connection);
		
		return connection;
	}

	/**
	 * @precondition connection != null
	 * @postcondition connections is connected
	 * 
	 * @param connection
	 */
	private static void openConnection(Connection connection) {
		connection.setLogin(Configuration.getUserInSession().getLogin());
		connection.setPassword(Configuration.getUserInSession().getPassword());
		connection.open();
	}
	
	/**
	 * @postcondition close the thread connection
	 */
	public static void closeConnection() {
		Connection connection = getConnections().get();
		
		if (connection != null) {
			getConnections().set(null);
			connection.setInUse(false);
		}
	}

	/**
	 * @precondition milliseconds > 0
	 * @postcondition the thread wait for x milliseconds
	 */
	private static void waitTime(int milliseconds) {
		if (milliseconds > 0) {
			try {
				Thread.sleep(milliseconds);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	//	GETs AND SETs
	private static ThreadLocal<Connection> getConnections() {
		return connections;
	}

	private static void setConnections(ThreadLocal<Connection> connections) {
		ConnectionPool.connections = connections;
	}

	private static Collection<Connection> getPoolConnections() {
		return poolConnections;
	}

	private static void setPoolConnections(Collection<Connection> poolConnections) {
		ConnectionPool.poolConnections = poolConnections;
	}
}
